/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.util;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Objects;

/**
 * @description: ObjectUtils
 * @author: zzh
 * @date: 2021/10/28 09:41
 */
public class ObjectUtils {

  private static final int INT_ZERO = 0;

  private static final double DOUBLE_ZERO = 0.0d;

  /**
   * 比较两个对象是否相等。<br>
   * 相同的条件有两个，满足其一即可：<br>
   *
   * <ol>
   *   <li>obj1 == null &amp;&amp; obj2 == null
   *   <li>obj1.equals(obj2)
   *   <li>如果是BigDecimal比较，0 == obj1.compareTo(obj2)
   * </ol>
   *
   * @param obj1 对象1
   * @param obj2 对象2
   * @return 是否相等
   * @see Objects#equals(Object, Object)
   */
  public static boolean equal(Object obj1, Object obj2) {
    if (obj1 instanceof BigDecimal && obj2 instanceof BigDecimal) {
      return equals((BigDecimal) obj1, (BigDecimal) obj2);
    }
    return Objects.equals(obj1, obj2);
  }

  /**
   * 空转0
   *
   * @param decimal {@link BigDecimal}，可以为{@code null}
   * @return {@link BigDecimal}参数为空时返回0的值
   */
  public static BigDecimal null2Zero(BigDecimal decimal) {

    return decimal == null ? BigDecimal.ZERO : decimal;
  }

  /**
   * 如果给定值为0，返回1，否则返回原值
   *
   * @param value 值
   * @return 1或非0值
   */
  public static int zero2One(int value) {
    return 0 == value ? 1 : value;
  }

  /**
   * 创建{@link BigInteger}，支持16进制、10进制和8进制，如果传入空白串返回null<br>
   * from Apache Common Lang
   *
   * @param str 数字字符串
   * @return {@link BigInteger}
   */
  public static BigInteger newBigInteger(String str) {
    str = StrUtils.trimToNull(str);
    if (null == str) {
      return null;
    }

    int pos = 0; // 数字字符串位置
    int radix = 10;
    boolean negate = false; // 负数与否
    if (str.startsWith("-")) {
      negate = true;
      pos = 1;
    }
    if (str.startsWith("0x", pos) || str.startsWith("0X", pos)) {
      // hex
      radix = 16;
      pos += 2;
    } else if (str.startsWith("#", pos)) {
      // alternative hex (allowed by Long/Integer)
      radix = 16;
      pos++;
    } else if (str.startsWith("0", pos) && str.length() > pos + 1) {
      // octal; so long as there are additional digits
      radix = 8;
      pos++;
    } // default is to treat as decimal

    if (pos > 0) {
      str = str.substring(pos);
    }
    final BigInteger value = new BigInteger(str, radix);
    return negate ? value.negate() : value;
  }

  /**
   * 比较大小，值相等 返回true<br>
   * 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
   * 此方法判断值相等时忽略精度的，即0.00 == 0
   *
   * @param num1 数字1
   * @param num2 数字2
   * @return 是否相等
   */
  public static boolean equals(double num1, double num2) {
    return Double.doubleToLongBits(num1) == Double.doubleToLongBits(num2);
  }

  /**
   * 比较大小，值相等 返回true<br>
   * 此方法通过调用{@link Float#floatToIntBits(float)}方法来判断是否相等<br>
   * 此方法判断值相等时忽略精度的，即0.00 == 0
   *
   * @param num1 数字1
   * @param num2 数字2
   * @return 是否相等
   */
  public static boolean equals(float num1, float num2) {
    return Float.floatToIntBits(num1) == Float.floatToIntBits(num2);
  }

  /**
   * 比较大小，值相等 返回true<br>
   * 此方法通过调用{@link BigDecimal#compareTo(BigDecimal)}方法来判断是否相等<br>
   * 此方法判断值相等时忽略精度的，即0.00 == 0
   *
   * @param bigNum1 数字1
   * @param bigNum2 数字2
   * @return 是否相等
   */
  public static boolean equals(BigDecimal bigNum1, BigDecimal bigNum2) {
    //noinspection NumberEquality
    if (bigNum1.equals(bigNum2)) {
      // 如果用户传入同一对象，省略compareTo以提高性能。
      return true;
    }
    if (bigNum1 == null || bigNum2 == null) {
      return false;
    }
    return 0 == bigNum1.compareTo(bigNum2);
  }

  /**
   * 比较两个字符是否相同
   *
   * @param c1 字符1
   * @param c2 字符2
   * @param ignoreCase 是否忽略大小写
   * @return 是否相同
   * @see CharUtils#equals(char, char, boolean)
   */
  public static boolean equals(char c1, char c2, boolean ignoreCase) {
    return CharUtils.equals(c1, c2, ignoreCase);
  }


  /**
   * 如果给定对象为{@code null}返回默认值
   *
   * <pre>
   * ObjectUtil.defaultIfNull(null, null)      = null
   * ObjectUtil.defaultIfNull(null, "")        = ""
   * ObjectUtil.defaultIfNull(null, "zz")      = "zz"
   * ObjectUtil.defaultIfNull("abc", *)        = "abc"
   * ObjectUtil.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
   * </pre>
   *
   * @param <T>          对象类型
   * @param object       被检查对象，可能为{@code null}
   * @param defaultValue 被检查对象为{@code null}返回的默认值，可以为{@code null}
   * @return 被检查对象为{@code null}返回默认值，否则返回原值
   */
  public static <T> T defaultIfNull(final T object, final T defaultValue) {
    return (null != object) ? object : defaultValue;
  }

  public static <T> T checkNotNull(T arg, String text) {
    if (arg == null) {
      throw new NullPointerException(text);
    }
    return arg;
  }

  /**
   * Checks that the given argument is strictly positive. If it is not, throws {@link IllegalArgumentException}.
   * Otherwise, returns the argument.
   */
  public static int checkPositive(int i, String name) {
    if (i <= INT_ZERO) {
      throw new IllegalArgumentException(name + " : " + i + " (expected: > 0)");
    }
    return i;
  }

  /**
   * Checks that the given argument is strictly positive. If it is not, throws {@link IllegalArgumentException}.
   * Otherwise, returns the argument.
   */
  public static double checkPositive(double i, String name) {
    if (i <= INT_ZERO) {
      throw new IllegalArgumentException(name + " : " + i + " (expected: > 0)");
    }
    return i;
  }
}
